﻿// Copyright (c) 2012 - 2020 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2018-12-05 version 3.1.5 Jared Zheng <jaredz at outlook dot com>

#include "stdafx.h"
#include "ServiceServerImp.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// CServiceServer
UInt CServiceServer::Command(PCXStr pszCMD, uintptr_t utParam)
{
    CString strCmd = pszCMD;
    if (strCmd == TF("ServerAck"))
    {
        m_nServerAck = (Int)utParam;
    }
    else if (strCmd == TF("SyncInfo"))
    {
        m_nSyncInfo = (Int)utParam;
    }
    else if (strCmd == TF("CommonEvent"))
    {
        m_nCommonEvent = (Int)utParam;
    }
    return (UInt)RET_OKAY;
}

UInt CServiceServer::Update(void)
{
    if (m_nStatus < STATUSS_ERROR)
    {
        // 定时更新线程异常导致不向同步管理发送心跳包, 会导致本服务器离线
        // 这里只要测试网络工作线程的异常就可以了
        if (m_NetworkPtr->Check(m_pConfig->GetUpdateTick() * DATAD_TIME))
        {
            m_ServerInfo.MayDay(); // 网络工作线程异常
            m_nStatus = STATUSS_ERROR;
            DEV_ERROR(TF("[业务功能]网络线程异常, 进入异常状态"));
            LOG_ERROR(m_FileLog, TF("[业务功能]网络线程异常, 进入异常状态"));
        }

        CheckConnectMasterServer();
        CheckConnectMasterDBServer();

        m_RoutinePtr->Update();
    }
    if (m_nStatus < STATUSS_STOP)
    {
        if (SyncServerInfo())
        {
            // unlink : tick thread exception
            // mayday : network & eventqueue thread exception
            return RET_OKAY;
        }
    }
    return RET_FAIL;
}
//--------------------------------------
UInt CServiceServer::Init(CEventHandler& EventHandlerRef, CServerConfig& ConfigRef)
{
    if (m_nStatus == STATUSS_NONE)
    {
        m_FileLog.Create(ConfigRef.GetLogPath(), CServerConfig::ServiceServer);
        LOG_INFO(m_FileLog, TF("[业务功能]初始化开始!"));
        m_MgrHandler = &EventHandlerRef;
        m_pConfig    = &ConfigRef;

        if (LoadConfig() == false)
        {
            return (UInt)RET_FAIL;
        }

        m_nStatus = STATUSS_INIT;
        LOG_INFO(m_FileLog, TF("[业务功能]初始化完成!"));
        return (UInt)RET_OKAY;
    }
    return (UInt)RET_FAIL;
}

bool CServiceServer::LoadConfig(void)
{
    assert(m_pConfig != nullptr);
    m_pConfig->Dump(m_FileLog, CServerConfig::CFG_LOAD_SERVICE); // 配置信息输出到日志文件

    // 从动态变量表获取网络层智能指针
    assert(m_NetworkPtr == nullptr);
    CKeyValue::VALUE xValue = {0};
    m_pConfig->GetKeyValue().GetValue(CServerConfig::NetworkPtr, xValue);
    if (xValue.pValue == nullptr)
    {
        LOG_ERROR(m_FileLog, TF("[业务功能]从动态变量表获取网络层智能指针无效"));
        return false;
    }
    m_NetworkPtr = *(reinterpret_cast<CNetworkPtr*>(xValue.pValue));

    assert(m_sConnectMaster == 0);
    assert(m_sConnectMasterDB == 0);

    m_ServerInfo.usId   = m_pConfig->GetServerId(CServerConfig::CFG_LOAD_SERVICE);
    m_ServerInfo.usIncr = m_pConfig->GetServerIncr(CServerConfig::CFG_LOAD_SERVICE);
    LOGV_INFO(m_FileLog, TF("[业务功能]从配置读取服务器Id=%d, Incr=%d!"), m_ServerInfo.usId, m_ServerInfo.usIncr);
    if (m_pConfig->GetNetworkAttr() & ATTR_IPV6)
    {
        m_ServerInfo.NetAddr[SERVICEI_MASTER].usAttr   = ATTR_IPV6;
        m_ServerInfo.NetAddr[SERVICEI_MASTERDB].usAttr = ATTR_IPV6;
    }

    STR_ADDR strAddr;
    m_pConfig->GetServerAddr(CServerConfig::CFG_LOAD_MASTER, CServerConfig::CFG_LOAD_NONE, strAddr);
    m_NetworkPtr->TranslateAddr(strAddr.strIp, strAddr.usPort, m_ServerInfo.NetAddr[SERVICEI_MASTER]); // master listen service

    m_pConfig->GetServerAddr(CServerConfig::CFG_LOAD_MASTERDB, CServerConfig::CFG_LOAD_NONE, strAddr);
    m_NetworkPtr->TranslateAddr(strAddr.strIp, strAddr.usPort, m_ServerInfo.NetAddr[SERVICEI_MASTERDB]); // masterdb listen service

    if (LoadExtConfig())
    {
        return true;
    }
    LOG_ERROR(m_FileLog, TF("[业务功能]创建例程处理失败"));
    return false;
}
//--------------------------------------
void CServiceServer::Exit(void)
{
    if (m_nStatus != STATUSS_NONE)
    {
        LOG_INFO(m_FileLog, TF("[业务功能]退出处理开始!"));
        m_MgrHandler = nullptr;

        UnloadConfig();

        m_nStatus = STATUSS_NONE;
        LOG_INFO(m_FileLog, TF("[业务功能]退出处理完成!"));
    }
}

void CServiceServer::UnloadConfig(void)
{
    m_pConfig    = nullptr;
    m_NetworkPtr = nullptr;

    assert(m_sConnectMaster   == 0);
    assert(m_sConnectMasterDB == 0);

    UnloadExtConfig();
}
//--------------------------------------
bool CServiceServer::Start(void)
{
    if (m_nStatus == STATUSS_INIT)
    {
        LOG_INFO(m_FileLog, TF("[业务功能]启动开始!"));

        if (m_RoutinePtr->Start(this) == false)
        {
            return false;
        }
        if ((StartConnectMasterServer()   == false) ||
            (StartConnectMasterDBServer() == false))
        {
            return false;
        }

        m_nStatus = STATUSS_RUN;
        LOG_INFO(m_FileLog, TF("[业务功能]启动完成!"));
    }
    return true;
}

bool CServiceServer::StartConnectMasterServer(void)
{
    if (m_sConnectMaster == 0)
    {
        STR_ADDR strAddr;
        m_pConfig->GetServerAddr(CServerConfig::CFG_LOAD_SERVICE, CServerConfig::CFG_LOAD_NONE, strAddr);
        m_sConnectMaster = m_NetworkPtr->Create(*this, strAddr.usPort, *strAddr.strIp);
    }
    if (m_sConnectMaster != 0)
    {
        LOG_INFO(m_FileLog, TF("[业务功能]创建连接业务管理服务器Socket成功"));
        if (m_nMasterLink == STATUSL_NONE)
        {
            STR_ADDR  strAddr;
            m_pConfig->GetServerAddr(CServerConfig::CFG_LOAD_MASTER, CServerConfig::CFG_LOAD_NONE, strAddr, true);

            m_nMasterLink = STATUSL_CNNTING;
            if (m_NetworkPtr->Connect(m_sConnectMaster, m_ServerInfo.NetAddr[SERVICEI_MASTER]) == false)
            {
                LOGV_WARN(m_FileLog, TF("[业务功能]连接业务管理服务器[%s]:%d请求失败"), *strAddr.strIp, strAddr.usPort);
            }
            else
            {
                LOGV_INFO(m_FileLog, TF("[业务功能]连接业务管理服务器[%s]:%d请求完成"), *strAddr.strIp, strAddr.usPort);
            }
        }
    }
    else
    {
        LOG_ERROR(m_FileLog, TF("[业务功能]创建连接业务管理服务器Socket失败"));
        return false;
    }
    return true;
}

bool CServiceServer::StartConnectMasterDBServer(void)
{
    if (m_ServerInfo.NetAddr[SERVICEI_MASTERDB].usPort == 0)
    {
        m_nMasterDBLink = STATUSL_RESERVED;
        m_MgrHandler->OnHandle(PAKE_LINK, 0, PAKT_MASTERDB);
        m_RoutinePtr->AddQueue(PAKE_LINKACK, (UInt)-1, PAKT_MASTERDB); // (UInt)-1
        LOG_INFO(m_FileLog, TF("[业务功能]不需要连接业务数据服务器"));
        return true;
    }
    if (m_sConnectMasterDB == 0)
    {
        STR_ADDR strAddr;
        m_pConfig->GetServerAddr(CServerConfig::CFG_LOAD_SERVICE, CServerConfig::CFG_LOAD_MASTERDB, strAddr);
        m_sConnectMasterDB = m_NetworkPtr->Create(*this, strAddr.usPort, *strAddr.strIp);
    }
    if (m_sConnectMasterDB != 0)
    {
        LOG_INFO(m_FileLog, TF("[业务功能]创建连接业务数据服务器Socket成功"));
        if (m_nMasterDBLink == STATUSL_NONE)
        {
            STR_ADDR  strAddr;
            m_pConfig->GetServerAddr(CServerConfig::CFG_LOAD_MASTERDB, CServerConfig::CFG_LOAD_NONE, strAddr, true);

            m_nMasterDBLink = STATUSL_CNNTING;
            if (m_NetworkPtr->Connect(m_sConnectMasterDB, m_ServerInfo.NetAddr[SERVICEI_MASTERDB]) == false)
            {
                LOGV_WARN(m_FileLog, TF("[业务功能]连接业务数据服务器[%s]:%d请求失败"), *strAddr.strIp, strAddr.usPort);
            }
            else
            {
                LOGV_INFO(m_FileLog, TF("[业务功能]连接业务数据服务器[%s]:%d请求完成"), *strAddr.strIp, strAddr.usPort);
            }
        }
    }
    else
    {
        LOG_ERROR(m_FileLog, TF("[业务功能]创建连接业务数据服务器Socket失败"));
        return false;
    }
    return true;
}
//--------------------------------------
bool CServiceServer::Pause(bool bPause)
{
    if (bPause && (m_nStatus == STATUSS_RUN))
    {
        m_nStatus = STATUSS_PAUSE;
        LOG_INFO(m_FileLog, TF("[业务功能]暂停服务"));
        m_RoutinePtr->Pause();
        return true;
    }
    else if ((bPause == false) && (m_nStatus == STATUSS_PAUSE))
    {
        m_nStatus = STATUSS_RUN;
        LOG_INFO(m_FileLog, TF("[业务功能]允许服务"));
        m_RoutinePtr->Pause(false);
        return true;
    }
    return false;
}
//--------------------------------------
void CServiceServer::Stop(void)
{
    if (m_nStatus > STATUSS_NONE)
    {
        LOG_INFO(m_FileLog, TF("[业务功能]停止开始!"));
        m_nStatus = STATUSS_STOP;

        m_nServerAck   = TRUE;
        m_nSyncInfo    = FALSE;
        m_nCommonEvent = FALSE;

        StopConnectMasterDBServer();
        StopConnectMasterServer();

        m_RoutinePtr->Stop();

        m_ServerInfo.Zero();

        m_nStatus = STATUSS_INIT;
        LOG_INFO(m_FileLog, TF("[业务功能]停止完成!"));
    }
}

void CServiceServer::StopConnectMasterServer(void)
{
    if (m_sConnectMaster != 0)
    {
        m_NetworkPtr->Destroy(m_sConnectMaster);
        m_sConnectMaster = 0;
        LOG_INFO(m_FileLog, TF("[业务功能]销毁连接业务管理服务器成功"));
    }
    m_nMasterLink = STATUSL_NONE;
}

void CServiceServer::StopConnectMasterDBServer(void)
{
    if (m_sConnectMasterDB != 0)
    {
        m_NetworkPtr->Destroy(m_sConnectMasterDB);
        m_sConnectMasterDB = 0;
        LOG_INFO(m_FileLog, TF("[业务功能]销毁连接业务数据服务器成功"));
    }
    m_nMasterDBLink = STATUSL_NONE;
}
//--------------------------------------
bool CServiceServer::OnTcpDispatch(const PacketPtr& PktPtr, PTCP_PARAM pTcp)
{
    // 1. PTCP_PARAM->pCache != nullptr时上层可以保存网络层申请的缓存数据
    //    PTCP_PARAM->pCache, PTCP_PARAM->index是网络层申请的缓存数据的起始地址和索引号
    // 2. PTCP_PARAM->pData为当前数据开始地址, PTCP_PARAM->stSize为当前数据大小
    // 3. 如果上层保存缓存, 设置PTCP_PARAM->pData为nullptr通知网络层不要再使用当前缓存
    // 4. 释放缓存使用MObject::sMCFree(index, pCache)
    bool bRet = true;
    if (PktPtr->GetEvent() != PAKE_LIVEACK)
    {
        switch (PktPtr->GetType())
        {
        case PAKT_MASTER:
            {
                bRet = DispatchMasterServer(PktPtr, pTcp);
            }
            break;
        case PAKT_MASTERDB:
            {
                bRet = DispatchMasterDBServer(PktPtr, pTcp);
            }
            break;
        default:
            {
                LOGV_WARN(m_FileLog, TF("[业务功能]%p无法识别的信令包类型[%d]数据[event=%d]"), pTcp->sSocket, PktPtr->GetType(), PktPtr->GetEvent());
                bRet = false;
            }
        }
    }
    return bRet;
}

bool CServiceServer::DispatchMasterServer(const PacketPtr& PktPtr, PTCP_PARAM pTcp)
{
    switch (PktPtr->GetEvent())
    {
    case PAKE_LINKACK:
        {
            if (PktPtr->GetAck() == (UACK)ERRORD_OKAY)
            {
                m_nMasterLink = STATUSL_LINKED;

                NET_ADDR NetAddr;
                m_NetworkPtr->GetAddr(pTcp->sSocket, NetAddr, false);
                m_MgrHandler->OnHandle(PAKE_LINK, reinterpret_cast<uintptr_t>(&NetAddr), PAKT_MASTER);
                LOG_INFO(m_FileLog, TF("[业务功能]收到业务管理服务器注册回复包"));
                if (m_nServerAck != FALSE)
                {
                    m_RoutinePtr->AddQueue(PAKE_LINKACK, PktPtr->GetSrvId(), PAKT_MASTER);
                }
            }
            else
            {
                m_nMasterLink = STATUSL_FAILED;
                LOGV_WARN(m_FileLog, TF("[业务功能]收到业务管理服务器注册回复包, 错误信息=%d"), PktPtr->GetAck());

                m_nStatus = STATUSS_OVER;
                m_ServerInfo.OverLoad();
                DEV_WARN(TF("[业务功能]收到业务管理服务器注册回复错误, 进入超载状态!"));
                LOG_WARN(m_FileLog, TF("[业务功能]收到业务管理服务器注册回复错误, 进入超载状态!"));
            }
        }
        break;
    case PAKE_UPDATEACK:
        {
            //DEV_INFO(TF("[业务功能]收到业务管理服务器更新回复包"));
        }
        break;
    case PAKE_UNLINKACK:
        {
            m_nMasterLink = STATUSL_CNNTED;
            LOG_INFO(m_FileLog, TF("[业务功能]收到业务管理服务器注销回复包"));
            if (m_nServerAck != FALSE)
            {
                m_RoutinePtr->AddQueue(PAKE_UNLINKACK, 0, PAKT_MASTER);
            }
        }
        break;
    default:
        {
            if ((PktPtr->GetEvent() >= PAKE_ROUTINE_BEGIN) && (PktPtr->GetEvent() <= PAKE_ROUTINE_FAIL))
            {
                m_RoutinePtr->AddQueue((Int)PktPtr->GetEvent(), *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
            }
            else if ((PktPtr->GetEvent() >= PAKE_SERVICE_BEGIN) && (PktPtr->GetEvent() <= PAKE_SERVICE_END))
            {
                m_RoutinePtr->AddQueue((Int)PktPtr->GetEvent(), *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
            }
            else if ((m_nCommonEvent != FALSE) &&
                     (PktPtr->GetEvent() >= PAKE_COMMON_BEGIN) &&
                     (PktPtr->GetEvent() <= PAKE_COMMON_END))
            {
                m_RoutinePtr->AddQueue((Int)PktPtr->GetEvent(), *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[业务网关]%p无法识别的业务管理服务器信令包数据[event=%d]"), pTcp->sSocket, PktPtr->GetEvent());
            }
        }
    }
    return true;
}

bool CServiceServer::DispatchMasterDBServer(const PacketPtr& PktPtr, PTCP_PARAM pTcp)
{
    switch (PktPtr->GetEvent())
    {
    case PAKE_LINKACK:
        {
            if (PktPtr->GetAck() == (UACK)ERRORD_OKAY)
            {
                m_nMasterDBLink = STATUSL_LINKED;

                NET_ADDR NetAddr;
                m_NetworkPtr->GetAddr(pTcp->sSocket, NetAddr, false);
                m_MgrHandler->OnHandle(PAKE_LINK, reinterpret_cast<uintptr_t>(&NetAddr), PAKT_MASTERDB);
                LOG_INFO(m_FileLog, TF("[业务功能]收到业务数据服务器注册回复包"));
                if (m_nServerAck != FALSE)
                {
                    m_RoutinePtr->AddQueue(PAKE_LINKACK, PktPtr->GetSrvId(), PAKT_MASTERDB);
                }
            }
            else
            {
                m_nMasterDBLink = STATUSL_FAILED;
                LOGV_WARN(m_FileLog, TF("[业务功能]收到业务数据服务器注册回复包, 错误信息=%d"), PktPtr->GetAck());

                m_nStatus = STATUSS_OVER;
                m_ServerInfo.OverLoad();
                DEV_WARN(TF("[业务功能]收到业务数据服务器注册回复错误, 进入超载状态!"));
                LOG_WARN(m_FileLog, TF("[业务功能]收到业务数据服务器注册回复错误, 进入超载状态!"));
            }
        }
        break;
    case PAKE_UPDATEACK:
        {
            //DEV_INFO(TF("[业务功能]收到业务数据服务器更新回复包"));
        }
        break;
    case PAKE_UNLINKACK:
        {
            m_nMasterDBLink = STATUSL_CNNTED;
            LOG_INFO(m_FileLog, TF("[业务功能]收到业务数据服务器注销回复包"));
            if (m_nServerAck != FALSE)
            {
                m_RoutinePtr->AddQueue(PAKE_UNLINKACK, 0, PAKT_MASTERDB);
            }
        }
        break;
    default:
        {
            if ((PktPtr->GetEvent() >= PAKE_ROUTINE_BEGIN) && (PktPtr->GetEvent() <= PAKE_ROUTINE_FAIL))
            {
                m_RoutinePtr->AddQueue((Int)PktPtr->GetEvent(), *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
            }
            else if ((PktPtr->GetEvent() >= PAKE_SERVICE_BEGIN) && (PktPtr->GetEvent() <= PAKE_SERVICE_END))
            {
                m_RoutinePtr->AddQueue((Int)PktPtr->GetEvent(), *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
            }
            else if ((m_nCommonEvent != FALSE) &&
                     (PktPtr->GetEvent() >= PAKE_COMMON_BEGIN) &&
                     (PktPtr->GetEvent() <= PAKE_COMMON_END))
            {
                m_RoutinePtr->AddQueue((Int)PktPtr->GetEvent(), *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[业务管理]%p无法识别的业务数据服务器信令包数据[event=%d]"), pTcp->sSocket, PktPtr->GetEvent());
            }
        }
    }
    return true;
}
//--------------------------------------
bool CServiceServer::OnTcpConnect(UInt uError, Socket sConnect)
{
    if (sConnect == m_sConnectMasterDB)
    {
        if (uError == 0)
        {
            m_nMasterDBLink = STATUSL_CNNTED;
            LinkMasterDBServer();
        }
        else
        {
            DEV_INFO(TF("[业务功能]连接业务数据服务器失败%X!"), uError);
            LOGV_WARN(m_FileLog, TF("[业务功能]连接业务数据服务器失败%X!"), uError);
        }
    }
    else
    {
        assert(sConnect == m_sConnectMaster);
        if (uError == 0)
        {
            m_nMasterLink = STATUSL_CNNTED;
            LinkMasterServer();
        }
        else
        {
            DEV_INFO(TF("[业务功能]连接业务管理服务器失败%X!"), uError);
            LOGV_WARN(m_FileLog, TF("[业务功能]连接业务管理服务器失败%X!"), uError);
        }
    }
    return true;
}

void CServiceServer::LinkMasterServer(void)
{
    if (m_nMasterLink == STATUSL_CNNTED)
    {
        m_ServerInfo.usStatus = STATUSU_LINK;

        CServiceLink Link;
        Link.SetServerStatus(m_ServerInfo);

        CStream& Stream = Link.Alloc(m_NetworkPtr);
        if (Stream.IsWrite())
        {
            m_ServerInfo.Addr(Stream);
            if (m_nSyncInfo != FALSE)
            {
                m_RoutinePtr->AddQueue(PAKE_LINK, Stream, PAKT_MASTER);
            }
            m_nMasterLink = STATUSL_LINKING;
            Link.Send(m_sConnectMaster, m_NetworkPtr);
        }
        else
        {
            DEV_WARN(TF("[业务功能]向业务管理服务器注册时创建网络数据流异常!"));
            LOG_WARN(m_FileLog, TF("[业务功能]向业务管理服务器注册时创建网络数据流异常!"));
        }
    }
}

void CServiceServer::UnlinkMasterServer(void)
{
    if (m_nMasterLink == STATUSL_LINKED)
    {
        m_nMasterLink = STATUSL_CNNTED;
        CTPAKHeadBase<PAKE_UNLINK, PAKT_SERVICE> Unlink;
        m_NetworkPtr->Send(m_sConnectMaster, Unlink);
    }
}

void CServiceServer::LinkMasterDBServer(void)
{
    if (m_nMasterDBLink == STATUSL_CNNTED)
    {
        m_ServerInfo.usStatus = STATUSU_LINK;

        CServiceLink Link;
        Link.SetServerStatus(m_ServerInfo);

        CStream& Stream = Link.Alloc(m_NetworkPtr);
        if (Stream.IsWrite())
        {
            m_ServerInfo.Addr(Stream);
            if (m_nSyncInfo != FALSE)
            {
                m_RoutinePtr->AddQueue(PAKE_LINK, Stream, PAKT_MASTERDB);
            }
            m_nMasterDBLink = STATUSL_LINKING;
            Link.Send(m_sConnectMasterDB, m_NetworkPtr);
        }
        else
        {
            DEV_WARN(TF("[业务功能]向业务数据服务器注册时创建网络数据流异常!"));
            LOG_WARN(m_FileLog, TF("[业务功能]向业务数据服务器注册时创建网络数据流异常!"));
        }
    }
}

void CServiceServer::UnlinkMasterDBServer(void)
{
    if (m_nMasterDBLink == STATUSL_LINKED)
    {
        m_nMasterDBLink = STATUSL_CNNTED;
        CTPAKHeadBase<PAKE_UNLINK, PAKT_SERVICE> Unlink;
        m_NetworkPtr->Send(m_sConnectMasterDB, Unlink);
    }
}
//--------------------------------------
bool CServiceServer::OnTcpClose(Socket sSocket, ULLong)
{
    if (m_nStatus == STATUSS_STOP)
    {
        return false;
    }
    if (sSocket == m_sConnectMaster)
    {
        m_sConnectMaster = 0;
        m_nMasterLink = STATUSL_NONE;
        m_MgrHandler->OnHandle(PAKE_UNLINK, 0, PAKT_MASTER);
        DEV_INFO(TF("[业务功能]连接业务管理服务器断开"));
        LOG_INFO(m_FileLog, TF("[业务功能]连接业务管理服务器断开"));
        if (m_nServerAck != FALSE)
        {
            m_RoutinePtr->AddQueue(PAKE_UNLINKACK, 0, PAKT_MASTER);
        }
    }
    else if (sSocket == m_sConnectMasterDB)
    {
        m_sConnectMasterDB = 0;
        m_nMasterDBLink = STATUSL_NONE;
        m_MgrHandler->OnHandle(PAKE_UNLINK, 0, PAKT_MASTERDB);
        DEV_INFO(TF("[业务功能]连接业务数据服务器断开"));
        LOG_INFO(m_FileLog, TF("[业务功能]连接业务数据服务器断开"));

        if (m_nServerAck != FALSE)
        {
            m_RoutinePtr->AddQueue(PAKE_UNLINKACK, 0, PAKT_MASTERDB);
        }
    }
    return true;
}
//--------------------------------------
bool CServiceServer::CheckConnectMasterServer(void)
{
    if (m_nMasterLink < STATUSL_CNNTED)
    {
        if (m_nMasterLink == STATUSL_NONE)
        {
            StartConnectMasterServer();
        }
        else
        {
            --m_nMasterLink;
        }
    }
    else if (m_nMasterLink < STATUSL_LINKED)
    {
        if (m_nMasterLink == STATUSL_CNNTED)
        {
            LinkMasterServer();
        }
        else
        {
            --m_nMasterLink;
        }
    }
    return true;
}

bool CServiceServer::CheckConnectMasterDBServer(void)
{
    if (m_nMasterDBLink < STATUSL_CNNTED)
    {
        if (m_nMasterDBLink == STATUSL_NONE)
        {
            StartConnectMasterDBServer();
        }
        else
        {
            --m_nMasterDBLink;
        }
    }
    else if (m_nMasterDBLink < STATUSL_LINKED)
    {
        if (m_nMasterDBLink == STATUSL_CNNTED)
        {
            LinkMasterDBServer();
        }
        else
        {
            --m_nMasterDBLink;
        }
    }
    return true;
}
//--------------------------------------
bool CServiceServer::SyncServerInfo(void)
{
    if (m_ServerInfo.usStatus == STATUSU_SYNC)
    {
        if (m_nMasterLink == STATUSL_LINKED)
        {
            CServiceUpdate Update;
            Update.SetServerStatus(m_ServerInfo);

            CStream& Stream = Update.Alloc(m_NetworkPtr);
            if (Stream.IsWrite())
            {
                m_ServerInfo.Addr(Stream);
                if (m_nSyncInfo != FALSE)
                {
                    m_RoutinePtr->AddQueue(PAKE_UPDATE, Stream, PAKT_MASTER);
                }
                Update.Send(m_sConnectMaster, m_NetworkPtr);
            }
        }
        if (m_nMasterDBLink == STATUSL_LINKED)
        {
            CServiceUpdate Update;
            Update.SetServerStatus(m_ServerInfo);

            CStream& Stream = Update.Alloc(m_NetworkPtr);
            if (Stream.IsWrite())
            {
                m_ServerInfo.Addr(Stream);
                if (m_nSyncInfo != FALSE)
                {
                    m_RoutinePtr->AddQueue(PAKE_UPDATE, Stream, PAKT_MASTERDB);
                }
                Update.Send(m_sConnectMasterDB, m_NetworkPtr);
            }
        }
        m_ServerInfo.usStatus = STATUSU_OKAY;
        return (m_MgrHandler->OnHandle(PAKE_SYNC, reinterpret_cast<uintptr_t>(&m_ServerInfo), PAKT_SERVICE) == RET_OKAY);
    }
    else
    {
        CTPAKHeadBase<PAKE_LIVE, PAKT_SERVICE> Live;
        Live.SetSrvId((USRVID)m_ServerInfo.usId);
        if (m_nMasterLink == STATUSL_LINKED)
        {
            m_NetworkPtr->Send(m_sConnectMaster, Live);
        }
        if (m_nMasterDBLink == STATUSL_LINKED)
        {
            m_NetworkPtr->Send(m_sConnectMasterDB, Live);
        }
    }
    return false;
}

bool CServiceServer::LoadExtConfig(void)
{
    CStringFix strPath;
    m_pConfig->GetServerExtConfig(CServerConfig::CFG_LOAD_SERVICE, strPath);

    LOGV_INFO(m_FileLog, TF("[业务功能]ExtConfig=%s"), *strPath);

    CFileReadStream Reader;
    if (Reader.Create(*strPath))
    {
        CKVNode  KVNode;
        CKVStore KVStore;
        if (KVStore.Load(KVNode, Reader))
        {
            if (KVNode.Find(TF("FrameworkRoutine")))
            {
                return LoadExtRoutine(KVNode);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[业务功能]无法找到ExtConfig=%s文件内的节点FrameworkRoutine"), *strPath);
            }
        }
        else
        {
            LOGV_WARN(m_FileLog, TF("[业务功能]解析ExtConfig=%s文件内容失败"), *strPath);
        }
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[业务功能]打开ExtConfig=%s文件不存在"), *strPath);
    }

    LOG_INFO(m_FileLog, TF("[业务功能]默认加载同目录下框架例程模块"));
    CStringKey strObjectKey = TF("C");
    strObjectKey += CServerConfig::ServiceRoutine;

    CStringKey strModuleKey = CServerConfig::CurFolder;
#if (__PLATFORM_TARGET__ == PLATFORM_TARGET_LINUX)
    strModuleKey += CServerConfig::LibPrefix;
#endif
    strModuleKey += CServerConfig::ServiceRoutine;
    strModuleKey += CServerConfig::LibExt;

    return CreateRTTIObject(*strObjectKey, CServerConfig::ServiceRoutine, *strModuleKey);
}

bool CServiceServer::LoadExtRoutine(CKVNode& Root)
{
    // {
    //     ...
    //     "FrameworkRoutine":{
    //         "Name": "Service-Routine",
    //         "Object": "Service-Routine class name",
    //         "Module": "Service-Routine module name",
    //     },
    //     "Time": 10,
    //  ...
    // }
    CKVString strName;
    CKVString strObject;
    CKVString strModule;

    CKVNode& Routine = Root[TF("FrameworkRoutine")];
    Routine[TF("Name")].GetString(strName);
    Routine[TF("Object")].GetString(strObject);
    Routine[TF("Module")].GetString(strModule);
#if (__PLATFORM_TARGET__ == PLATFORM_TARGET_LINUX)
    strModule.Insert(0, CServerConfig::LibPrefix);
#endif
    strModule += CServerConfig::LibExt;

    return CreateRTTIObject(*strObject, *strName, *strModule);
}

bool CServiceServer::CreateRTTIObject(PCXStr pszObject, PCXStr pszName, PCXStr pszModule)
{
    assert(m_RoutinePtr == nullptr);
    if (CObjectTraits::Load<ICommonRoutine>(pszName, pszModule, m_RoutinePtr, pszObject))
    {
        LOGV_INFO(m_FileLog, TF("[业务功能]RTTI load --- Object=%s, Name=%s, Module=%s --- %p"), pszObject, pszName, pszModule, m_RoutinePtr.Get());
        return (m_RoutinePtr->Init() == (UInt)RET_OKAY);
    }
    LOGV_ERROR(m_FileLog, TF("[业务功能]RTTI load --- Object=%s, Name=%s, Module=%s --- Failed!"), pszObject, pszName, pszModule);
    return false;
}

bool CServiceServer::UnloadExtConfig(void)
{
    return UnloadExtRoutine();
}

bool CServiceServer::UnloadExtRoutine(void)
{
    if (m_RoutinePtr != nullptr)
    {
        CString strName = m_RoutinePtr->GetRTTI().GetName();
        m_RoutinePtr->Exit();
        m_RoutinePtr = nullptr;
        CObjectTraits::Unload<ICommonRoutine>(*strName);
        return true;
    }
    return false;
}

